#※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※
# File Name: git.sh
# Author: GID5564
# Description: function for git
# Created Time: 09/03/23-18:25:31
#※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※
#! /usr/bin/bash


##♥.git文件夹
#HEAD #指向当前分支 
#branches/ # 目录 
#config # 项目特有的配置选项 
#description # 仅供 GitWeb 程序使用 
#hooks/ # 保存了客户端或服务端钩子脚本 
#index # 保存了暂存区域信息 
#info/ # 保存了一份不希望在 .gitignore 文件中管理的忽略模式 (ignored patterns) 的全局可执行文件 
#objects/ # 存储所有数据内容 
#refs/ # 存储指向数据 (分支) 的提交对象的指针

##♥清理大文件步骤:
# 一：查询最大的三个文件的信息
#git verify-pack -v .git/objects/pack/pack-*.idx | sort -k 3 -g | tail -3

# 二: 查询对应文件的位置和文件名
#git rev-list --objects --all | grep 对应文件的编码（上面命令结果中获取）

# 三: 处理文件，将文件从历史记录中移除
#git filter-branch --index-filter 'git rm --cached --ignore-unmatch  文件名（带路径，上面命令结果中获取）'
# 四:清理
#rm -rf .git/refs/original
#git reflog expire --expire=now --all
#git fsck --full --unreachable
#git repack -A -d
#git gc --aggressive --prune=now

# 五: 提交
#git push --force


# 避免重复导入
#[[ -n $__XLIB_IMPORTED__GIT ]] && return 0
#__XLIB_IMPORTED__GIT=1

function __git_init__() {

    #设置自己的名字和电子邮件
    git config --global user.name "gid5564"
    git config --global user.email "94010902@qq.com"
}

function get_repo(){
    local cur=$(pwd)
    local repo=$(git remote -v 2>/dev/null | head -1 | awk -F" " '{print $2}')
    echo $repo
    unset repo
}


# 获取当前git所有的分支，并去除文件和Head分支
function GetBranchs(){
  local index=1
  local all_branchs=()

  for branch in $(git branch -a)
  do
    branch_simple_name=`echo $branch | grep '/' | cut -d '/' -f 3`;
    if [[ "$branch_simple_name" != "" && "$branch_simple_name" != "HEAD" ]]; 
    then
      all_branchs[index]="$branch_simple_name"
      let "index++"
    fi;
  done;
  echo all_branchs
  unset index
  unset all_branchs
  unset branch_simple_name
}


#判断一个路径是否是git仓库
function IsGit(){
    local cur=$(pwd)
    local d_path=${1:-${cur}}
    [[ -d ${d_path} ]] &&{
        cd ${d_path}
        local g_status=$(git rev-parse --is-inside-work-tree 2>/dev/null)
        [[ ${g_status} = 'true' ]] && echo 1 || echo 0 #1,是仓库 0,不是仓库
        unset g_status
    } || echo 2 #不是目录
    cd ${cur}
    unset d_path cur
}

#判断git工作目录是否干净
function HasUpdate(){
    local cur=$(pwd)
    local d_path=${1:-${cur}}
    
    local isg=$(IsGit ${d_path})
    [[ ${isg} -eq 1 ]] && {
        cd ${d_path}
        local g_status=$(git status -s 2>/dev/null)
        [[ -n ${g_status} ]] && echo 1 || echo 0   #1,有更改 0,未更攻
        unset g_status
    } || echo 2 #不是仓库
    cd ${cur}
    unset d_path cur isg
}

function UpdateLocalGit() {
    local cur=$(pwd)
    local d_path=$1
    local GIT_BRANCH=${2:-'master'}
    local ret

    local isg=$(HasUpdate ${d_path})
    if [[ ${isg} -eq 1 ]];then
        tip "${BLUE}更新本地git仓库: [${RESET}${YELLOW}${d_path}${RESET}${BLUE}]${RESET}"
        cd ${d_path}
	    git reset --hard origin/${GIT_BRANCH}
	    git pull --rebase --stat origin ${GIT_BRANCH} --allow-unrelated-histories || git rebase --skip
	    ret=$?
	    case "${ret}" in
	    0) ;;
	    *)
		    git fetch --depth=2
		    git reset --hard
		    git pull --rebase --stat --allow-unrelated-histories || git rebase --skip
		    ret=$?
		    ;;
	    esac
        if [[ ${ret} -eq 0 ]];then
            display_status "success"
        else
            display_status "failed"
        fi
	fi
	cd ${cur}
	unset cur
    unset d_path
    unset GIT_BRANCH
    unset ret
    unset isg
}

#更新远程git仓库
function UpdateRemoteGit(){
    local cur=$(pwd)
    local d_path=$1
    local comm=$2 #aidlux 控制台启动配置
    local GIT_BRANCH=${3:-'master'}
    
    local isg=$(HasUpdate ${d_path})
    if [[ ${isg} -eq 1 ]];then
        tip "${BLUE}更新远程git仓库: [${RESET}${YELLOW}${d_path}${RESET}${BLUE}]${RESET}"
        cd ${d_path}
        git add .
        git commit -m ${comm}
        git push origin ${GIT_BRANCH} --force
        if [[ $? -eq 0 ]];then
            display_status "success"
        else
            display_status "failed"
        fi
    fi
    cd ${cur}
    unset isg
    unset cur
    unset d_path
    unset comm
    unset GIT_BRANCH
}

#创建仓库
function new_git(){
    local git_name=$1
    local repo=$2
    local git_dir=$3
    local cur=$(pwd)
    [[ -z ${git_name} || -z ${repo} ]] && {
        error "Usage: new_git <name> <repo> [dir]"
        return $INVALID_ARGUMENTS
    }
    local isl=$(IsLink ${repo})
    [[ ${isl} -eq 0 ]] && {
        error "${repo} 地址错误!"
        return $INVALID_ARGUMENTS
    }

    [[ -z ${git_dir} || ! -d ${git_dir} ]] && {
        git_dir=${cur}
    }
    
    cd ${git_dir}
    mkdir ${git_name}
    cd ${git_name}
    
    git init 
    touch README.md
    git add README.md
    git commit -m "first commit"
    git remote add origin "${repo}/${git_name}.git"
    git push -u origin "master"
    if [ "$?" = "0" ];then
            success "创建GIT仓库[${git_name}]成功! ${RESET}${RED}${repo}/${git_name}.git${RESET}"
    else
            error "创建GIT仓库[${git_name}]失败!"
    fi
    cd ${cur}
    unset git_name
    unset git_dir
    unset repo
    unset cur
    unset isl
}


#删除仓库
function DeleteRemoteGit(){
    local repo_name=$1
    
    if [[ -z ${repo_name} ]];then
        error "${RED}仓库名称不能为空。${RESET}"
        return 1
    fi
    git remote rm ${repo_name}
    if [ "$?" = "0" ];then
        success "${GREEN}删除远程仓库${repo_name}成功!${RESET}"
    else
        error "${RED}删除远程仓库${repo_name}失败!${RESET}"
    fi
    unset repo_name
}

#删除仓库预存中的大文件
#查看仓库文件命令: git rev-list --objects --all
function RemoveBigFile(){
    local file=$1
    git filter-branch -f --tree-filter "rm -f ${file}" --tag-nam    e-filter cat -- --all
    git push origin --tags --force
    git push origin --all --force
    unset file
}


#清理本地与远程仓库缓存文件，达到瘦身效果，过程较慢
function clear_cache(){
    git push origin --force --all
    git remote prune origin  
    rm -Rf .git/refs/original
    rm -Rf .git/logs/
    git gc
    git prune
}



function UpdateDown(){
    local cur=$(pwd)
    local d_dir=$1
    local repo=$2
    local re='^(git|https):\/\/((\w+)\.){0,3}(\w+)(\/(\w+))*'

    [[ ! -d ${d_dir} ]] && {
        mkdir -p ${d_dir}
    }
    [[ -d ${d_dir}/.git ]] && {
            UpdateLocalGit ${d_dir}
    } || {
        [[ -n ${repo} ]] && {
            [[ ${repo} =~ ${re} ]] && {
                git clone ${repo} ${d_dir}
            }
        }
    }
}





__git_init__
























